// Copyright (c) 2025, the Dart project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

import 'dart:convert';
import 'dart:io';

import 'package:args/args.dart';
import 'package:json_schema/json_schema.dart';
import 'package:json_syntax_generator/json_syntax_generator.dart';
import 'package:native_test_helpers/native_test_helpers.dart';

void main(List<String> args) {
  final packageRoot = findPackageRoot('pub_formats');

  final stopwatch = Stopwatch()..start();
  final parser = ArgParser()
    ..addFlag(
      'set-exit-if-changed',
      negatable: false,
      help: 'Return a non-zero exit code if any files were changed.',
    )
    ..addFlag(
      'dump',
      abbr: 'd',
      negatable: false,
      help: 'Dump analyzed schema to .g.txt file.',
    );
  final argResults = parser.parse(args);

  final setExitIfChanged = argResults['set-exit-if-changed'] as bool;
  final dumpAnalyzedSchema = argResults['dump'] as bool;
  var generatedCount = 0;
  var changedCount = 0;

  for (final name in [
    'package_config',
    'package_graph',
    'pubspec_lock',
    'pubspec',
  ]) {
    final schemaFile = File.fromUri(
      packageRoot.resolve('doc/schema/${name}.schema.json'),
    );
    final schemaJson = jsonDecode(schemaFile.readAsStringSync());
    final schema = JsonSchema.create(schemaJson);

    final analyzedSchema = SchemaAnalyzer(
      schema,
      nameOverrides: {'path': 'path\$'},
      publicSetters: ['PubspecYamlFile'],
      publicValidators: ['PubspecYamlFile'],
    ).analyze();
    final textDumpFile = File.fromUri(
      packageRoot.resolve('lib/src/${name}_syntax.g.txt'),
    );
    final newTextDumpContent = analyzedSchema.toString();
    if (dumpAnalyzedSchema) {
      var oldTextDumpContent = '';
      if (textDumpFile.existsSync()) {
        oldTextDumpContent = textDumpFile.readAsStringSync();
      }
      if (oldTextDumpContent != newTextDumpContent) {
        textDumpFile.writeAsStringSync(newTextDumpContent);
        print('Generated ${textDumpFile.uri}');
        changedCount += 1;
      }
      generatedCount += 1;
    } else if (textDumpFile.existsSync()) {
      textDumpFile.deleteSync();
      print('Deleted ${textDumpFile.uri}');
      changedCount += 1;
    }

    final output = SyntaxGenerator(
      analyzedSchema,
      header: '''
// This file is generated, do not edit.
// File generated by pkgs/pub_formats/tool/generate.dart. 
// Must be rerun when pkgs/pub_formats/doc/schema/ is modified.
''',
    ).generate();
    final outputUri = packageRoot.resolve('lib/src/${name}_syntax.g.dart');
    final outputFile = File.fromUri(outputUri);
    var oldOutputContent = '';
    if (outputFile.existsSync()) {
      oldOutputContent = outputFile.readAsStringSync();
    }

    if (oldOutputContent != output) {
      outputFile.writeAsStringSync(output);
    }

    Process.runSync(Platform.executable, ['format', outputUri.toFilePath()]);

    final newOutputContent = outputFile.readAsStringSync();

    final newContentNormalized = newOutputContent.replaceAll('\r\n', '\n');
    final oldContentNormalized = oldOutputContent.replaceAll('\r\n', '\n');
    if (newContentNormalized != oldContentNormalized) {
      print('Generated $outputUri');
      changedCount += 1;
    }
    generatedCount += 1;
  }

  stopwatch.stop();
  final duration = stopwatch.elapsedMilliseconds / 1000.0;
  print(
    'Generated $generatedCount files ($changedCount changed) in '
    '${duration.toStringAsFixed(2)} seconds.',
  );
  if (setExitIfChanged && changedCount > 0) {
    exit(1);
  }
}
